home *** CD-ROM | disk | FTP | other *** search
/ Delphi Anthology / aDELPHI.iso / Runimage / Delphi50 / Source / Decision Cube / mxgrid.pas < prev    next >
Pascal/Delphi Source File  |  1999-08-11  |  76KB  |  2,395 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {       Borland Delphi Visual Component Library         }
  4. {                                                       }
  5. {       Copyright (c) 1997,99 Inprise Corporation       }
  6. {                                                       }
  7. {*******************************************************}
  8.  
  9. unit mxgrid;
  10.  
  11. interface
  12.  
  13. uses
  14.   Windows, SysUtils, Classes, Dialogs, Controls, StdCtrls, Graphics, DB,
  15.   Menus, Grids, Forms, mxarrays, mxConsts, MXDB, mxbutton, mxcommon, ImgList;
  16.  
  17. type
  18.   TValueArray = class(TSmallIntArray);
  19.   TDecisionGridOption = (cgGridLines, cgOutliner, cgPivotable);
  20.  
  21.   TDecisionGridOptions = set of TDecisionGridOption;
  22.  
  23.   TDecisionGridState = (csNormal, csPivoting);
  24.   TDecisionDrawStates = (dsGroupStart, dsRowCaption, dsColCaption, dsSum,
  25.                          dsRowValue, dsColValue, dsData, dsOpenAfter, dsCloseAfter,
  26.                          dsCloseBefore, dsOpenBefore, dsRowIndicator, dsColIndicator,
  27.                          dsRowPlus, dsColPlus, dsNone);
  28.   TDecisionPivotState = (psNone, psLeftPivot, psMiddlePivot, psRightPivot, psTopPivot);
  29.   TDecisionDrawState = set of TDecisionDrawStates;
  30.  
  31.   TDecisionDrawCellEvent = procedure (Sender: TObject; Col, Row: Longint;
  32.                                       var Value: string; var aFont: TFont;
  33.                                       var aColor: TColor; AState: TGridDrawState;
  34.                                       aDrawState: TDecisionDrawState) of Object;
  35.  
  36.   TDecisionExamineCellEvent = procedure (Sender: TObject; iCol, iRow: Longint;
  37.                                          iSum: Integer; const ValueArray: TValueArray) of Object;
  38.  
  39.   TDecisionCellType = (ctNone, ctCaptionRow, ctCaptionCol, ctNewCaptionCol,
  40.                        ctRowLabel, ctColLabel, ctData, ctRowPlus, ctColPlus,
  41.                        ctRowIndicator, ctColIndicator);
  42.  
  43.   TButtonPlace = (bpLeft, bpMiddle, bpRight);
  44.  
  45.   TCustomDecisionGrid = class;
  46.  
  47.   TDecisionGridDataLink = class(TDecisionDataLink)
  48.   private
  49.     FGrid: TCustomDecisionGrid;
  50.   protected
  51.     procedure DecisionDataEvent(Event: TDecisionDataEvent); override;
  52.   public
  53.     constructor Create(AGrid: TCustomDecisionGrid);
  54.     destructor Destroy; override;
  55.   end;
  56.  
  57.   TDDNotifyType = (tdDisplay, tdSubTotals, tdMetaData);
  58.  
  59.   TDisplayDim = class(TCollectionItem)
  60.   private
  61.     FName: String;
  62.     FFieldName: String;
  63.     FFormat: String;
  64.     FAlignment: TAlignment;
  65.     FColor: TColor;
  66.     FSubs: Boolean;
  67.     FOwner: TCollection;
  68.     procedure SetName(Value: string);
  69.     procedure SetFieldName(Value: string);
  70.     procedure SetFormat(Value: String);
  71.     procedure SetAlignment(Value: TAlignment);
  72.     procedure SetColor(Value: TColor);
  73.     procedure SetSubs(Value: Boolean);
  74.     procedure NotifyCollection(aType: TDDNotifyType);
  75.   protected
  76.   public
  77.     constructor Create(Collection: TCollection); override;
  78.     procedure assign(Value: TPersistent); override;
  79.   published
  80.     property DisplayName: string read FName write SetName;
  81.     property FieldName: string read FFieldName write SetFieldName;
  82.     property Color: TColor read FColor write SetColor;
  83.     property Format: String read FFormat write SetFormat;
  84.     property Alignment: TAlignment read FAlignment write SetAlignment;
  85.     property Subtotals: Boolean read FSubs write SetSubs;
  86.   end;
  87.  
  88.   TDisplayDimClass = class of TDisplayDim;
  89.  
  90.   TDisplayDims = class(TCollection)
  91.   private
  92.     bQuiet: boolean;
  93.     function GetDisplayDim(Index: Integer): TDisplayDim;
  94.     procedure SetDisplayDim(Index: Integer; Value: TDisplayDim);
  95.     constructor Create(Grid: TCustomDecisionGrid; ItemClass: TDisplayDimClass);
  96.   protected
  97.     FGrid: TCustomDecisionGrid;
  98.     function GetOwner: TPersistent; override;
  99.     procedure NotifyOwner(aType: TDDNotifyType);
  100.   public
  101.     property Items[Index: Integer]:TDisplayDim read GetDisplayDim write SetDisplayDim; default;
  102.   end;
  103.  
  104.   TCustomDecisionGrid = class(TCustomGrid)
  105.   private
  106.     FActiveGrid: boolean;
  107.     FMenu: TQuickMenu;
  108.     FDataLink: TDecisionGridDataLink;
  109.     FDisplayDims: TDisplayDims;
  110.     FOptions: TDecisionGridOptions;
  111.     FIndicators: TImageList;
  112.     FSourceCell: TGridCoord;               { grid coords of cell user began dragging or pivoting }
  113.     FTargetCell: TGridCoord;               { grid coords of target cell (is updated each mouse move }
  114.     FTargetSwitch: Boolean;
  115.     FCaptionRow: Byte;                    { = 0,1,2 caption row active, and are there any inactive categories }
  116.     FCaptionCol: Byte;                    { = 0,1,2 caption row active, and are there any inactive categories }
  117.     FChanging: Boolean;
  118.     FRowOffset: Byte;
  119.     fColOffset: Byte;
  120.     FActRows: Integer;
  121.     FActCols: Integer;
  122.     FTotRows: Integer;
  123.     FTotCols: Integer;
  124.     FColWidth: Integer;
  125.     FRowHeight: Integer;
  126.     FLabelFont: TFont;
  127.     FLabelColor: TColor;
  128.     FLabelSumColor: TColor;
  129.     FCaptionColor: TColor;
  130.     FCaptionFont: TFont;
  131.     FDataFont: TFont;
  132.     FDataColor: TColor;
  133.     FDataSumColor: TColor;
  134.     FGridLineColor: TColor;
  135.     FGridLineWidth: Integer;
  136.     FShowCubeEditor:boolean;
  137.     FOnDecisionExamineCell: TDecisionExamineCellEvent;
  138.     FOnDecisionDrawCell: TDecisionDrawCellEvent;
  139.     FOnTopLeftChanged: TNotifyEvent;
  140.     procedure InvalidateTargetCell;
  141.     function GetHorzButtonPlace(X,Y: Integer): TButtonPlace;
  142.     procedure PerformPivot;
  143.     procedure RawToDataCoord(var X,Y: LongInt);
  144.     procedure DataToRawCoord(var X,Y: LongInt);
  145.     function DataToRawX(X: LongInt): LongInt;
  146.     function DataToRawY(Y: LongInt): LongInt;
  147.     procedure DrawSpecialState(ACanvas: TCanvas; ARect: TRect;
  148.                                DrawState: TDecisionDrawState; PivotState: TDecisionPivotState);
  149.     function GetSpecialState(ARow,AColumn: Integer): TDecisionPivotState;
  150.     function GetDataPoint(ARow,AColumn: LongInt;  var State: TDecisionDrawState; var Alignment: TAlignment): String;
  151.     function WhichCoord( Coord: TGridCoord ): TDecisionCellType;
  152.     function WhichCoordExCap( Coord: TGridCoord ): TDecisionCellType;
  153.     function GetDimensionIndex(cellType: TDecisionCellType; Coord: TGridCoord;
  154.                                var dimGroup: TDimGroup;var bExists: Boolean): Integer;
  155.     function  MouseToDataCoord( X,Y: Integer): TGridCoord;
  156.     procedure SetNearestTargetCell(X,Y: Integer);
  157.     procedure GetHitTypes(ARow,AColumn: Integer; var ValueIndex: Integer;
  158.                           var DrawState: TDecisionDrawState; var CellType: TDecisionCellType);
  159.     procedure NewDataStructure;
  160.     procedure NewGridLayout;
  161.     function GetData(ARow, AColumn: Integer; var SubLevel: Integer): string;
  162.     function GetCaption(dimGroup: TDimGroup; Index: Integer): string;
  163.     function GetLabel(dimGroup: TDimGroup; Index: Integer; ValueIndex: Integer): string;
  164.     function GeTDecisionSource: TDecisionSource;
  165.     procedure SeTDecisionSource(Value: TDecisionSource);
  166.     procedure SetColWidth(Value: Integer);
  167.     procedure SetRowHeight(Value: Integer);
  168.     procedure SetGridLineWidth(Value: Integer);
  169.     procedure SetGridLineColor(Value: TColor);
  170.     procedure SetLabelFont(Value: TFont);
  171.     procedure SetLabelColor(Value: TColor);
  172.     procedure SetLabelSumColor(Value: TColor);
  173.     procedure SetCaptionFont(Value: TFont);
  174.     procedure SetCaptionColor(Value: TColor);
  175.     procedure SetDataFont(Value: TFont);
  176.     procedure SetDataColor(Value: TColor);
  177.     procedure SetDataSumColor(Value: TColor);
  178.     procedure FontChanged(Sender: TObject);
  179.     procedure SetOptions(Value: TDecisionGridOptions);
  180.     procedure CMDesignHitTest(var Msg: TCMDesignHitTest); message CM_DESIGNHITTEST;
  181.     procedure RightMouse(Sender: TObject);
  182.     procedure SelectDimOptions(Sender: TObject);
  183.     procedure SelectGridOptions(Sender: TObject);
  184.     procedure InitializeGridCells;
  185.     procedure SetTotals(Value: boolean);
  186.     function GetTotals: boolean;
  187.     function GetFixedRows: integer;
  188.     function GetFixedCols: integer;
  189.     function GetRowCount: integer;
  190.     function GetColCount: integer;
  191.     property ColWidth: Integer read FColWidth write SetColWidth;
  192.     property RowHeight: Integer read FRowHeight write SetRowHeight;
  193.   protected
  194.     FGridStateX: TDecisionGridState;
  195.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  196.     procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  197.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  198.     procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
  199.     function SelectCell(Arow, AColumn:LongInt): Boolean; override;
  200.     procedure TopLeftChanged; override;
  201.     procedure ColWidthsChanged; override;
  202.     procedure RowHeightsChanged; override;
  203.     procedure Paint; override;
  204.     property Options: TDecisionGridOptions read FOptions write SetOptions default [cgGridLines, cgOutLiner, cgPivotable];
  205.     property GridLineWidth: Integer read FGridLineWidth write SetGridLineWidth;
  206.     property GridLineColor: TColor read FGridLineColor write SetGridLineColor;
  207.     property CaptionFont: TFont read FCaptionFont write SetCaptionFont;
  208.     property CaptionColor: TColor read FCaptionColor write SetCaptionColor;
  209.     property DataFont: TFont read FDataFont write SetDataFont;
  210.     property DataColor: TColor read FDataColor write SetDataColor;
  211.     property DataSumColor: TColor read FDataSumColor write SetDataSumColor;
  212.     property LabelFont: TFont read FLabelFont write SetLabelFont;
  213.     property LabelColor: TColor read FLabelColor write SetLabelColor;
  214.     property LabelSumColor: TColor read FLabelSumColor write SetLabelSumColor;
  215.     property Dimensions: TDisplayDims read FDisplayDims write FDisplayDims;
  216.     function GetCells(ACol, ARow: Integer): String;
  217.     property FixedRows:integer read GetFixedRows;
  218.     property RowCount:integer read GetRowCount;
  219.     property FixedCols:integer read GetFixedCols;
  220.     property ColCount:integer read GetColCount;
  221.     property DefaultColWidth: Integer read FColWidth write SetColWidth;
  222.     property DefaultRowHeight: Integer read FRowHeight write SetRowHeight;
  223.   public
  224.     constructor Create(AOwner: TComponent); override;
  225.     destructor Destroy; override;
  226.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  227.     property DecisionSource: TDecisionSource read GeTDecisionSource write SeTDecisionSource;
  228.     function CellRect(ACol, ARow: Longint): TRect;
  229.     function CellValueArray(ACol, ARow: Integer; var ValueArray: TValueArray): boolean;
  230.     function CellDrawState(ACol, ARow: Integer; var Value: string; var DrawState: TDecisionDrawState): boolean;
  231.     property Totals: boolean read GetTotals write SetTotals;
  232.     property OnDecisionExamineCell: TDecisionExamineCellEvent read FOnDecisionExamineCell write FOnDecisionExamineCell;
  233.     property OnDecisionDrawCell: TDecisionDrawCellEvent read FOnDecisionDrawCell write FOnDecisionDrawCell;
  234.     property OnTopLeftChanged: TNotifyEvent read FOnTopLeftChanged write FOnTopLeftChanged;
  235.     property Cells[ACol, ARow: Integer]: String read GetCells;
  236.     property ShowCubeEditor:boolean read FShowCubeEditor write FShowCubeEditor;
  237.   end;
  238.  
  239.   TDecisionGrid = class(TCustomDecisionGrid)
  240.   public
  241.     property RowCount;
  242.     property ColCount;
  243.     property FixedRows;
  244.     property FixedCols;
  245.   published
  246.     property Options;
  247.     property DefaultColWidth;
  248.     property DefaultRowHeight;
  249.     property CaptionColor;
  250.     property CaptionFont;
  251.     property DataColor;
  252.     property DataSumColor;
  253.     property DataFont;
  254.     property LabelFont;
  255.     property LabelColor;
  256.     property LabelSumColor;
  257.     property DecisionSource;
  258.     property Dimensions;
  259.     property Totals;
  260.     property ShowCubeEditor;
  261.     { Inherited properties and events }
  262.     property Align;
  263.     property Anchors;
  264.     property BorderStyle;
  265.     property Color;
  266.     property Constraints;
  267.     property Ctl3D;
  268.     property DefaultDrawing;
  269.     property DragCursor;
  270.     property DragMode;
  271.     property Enabled;
  272.     property GridLineWidth;
  273.     property GridLineColor;
  274.     property ParentColor;
  275.     property ParentCtl3D;
  276.     property ParentFont;
  277.     property ParentShowHint;
  278.     property PopupMenu;
  279.     property ScrollBars;
  280.     property ShowHint;
  281.     property TabOrder;
  282.     property TabStop;
  283.     property Visible;
  284.     property OnClick;
  285.     property OnDblClick;
  286.     property OnDragDrop;
  287.     property OnDragOver;
  288.     property OnDecisionDrawCell;
  289.     property OnDecisionExamineCell;
  290.     property OnEndDrag;
  291.     property OnEnter;
  292.     property OnExit;
  293.     property OnKeyDown;
  294.     property OnKeyPress;
  295.     property OnKeyUp;
  296.     property OnMouseDown;
  297.     property OnMouseMove;
  298.     property OnMouseUp;
  299.     property OnResize;
  300.     property OnStartDrag;
  301.     property OnTopLeftChanged;
  302.   end;
  303.  
  304. implementation
  305.  
  306. uses Math;
  307.  
  308. type
  309.   BitmapId = (biLeftArrow, biRightArrow, biCaption, biPivot, biDOpen, biDClose);
  310.  
  311.   TDecisionCoord = Record
  312.     XY: TGridCoord;
  313.     CellType: TDecisionCellType;
  314.   end;
  315.  
  316. const
  317.   PlusWidth = 16;
  318.   NoSpace = 0;
  319.   SubTotal = -1;
  320.   BitmapArray: Array[BitmapId] of String = ('LeftArrow', 'RightArrow', 'Caption', 'Pivot', 'DOpen', 'DClose');
  321.  
  322. var
  323.   DrawBitmap: TBitmap;
  324.   UserCount: Integer;
  325.  
  326. procedure UsesBitmap;
  327. begin
  328.   if (UserCount = 0) then DrawBitmap := TBitmap.Create;
  329.   Inc(UserCount);
  330. end;
  331.  
  332. procedure ReleaseBitmap;
  333. begin
  334.   Dec(UserCount);
  335.   if (UserCount = 0) then DrawBitmap.Free;
  336. end;
  337.  
  338. procedure WriteText(ACanvas: TCanvas; ARect: TRect; DX, DY: Integer;
  339.   const Text: string; Alignment: TAlignment);
  340. const
  341.   AlignFlags : array [TAlignment] of Integer =
  342.     (DT_LEFT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX,
  343.      DT_RIGHT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX,
  344.      DT_CENTER or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX);
  345. var
  346.   B, R: TRect;
  347.   Left: Integer;
  348.   I: TColorRef;
  349. begin
  350.   I := ColorToRGB(ACanvas.Brush.Color);
  351.   if (GetNearestColor(ACanvas.Handle, I) = I) then
  352.   begin                       { Use ExtTextOut for solid colors }
  353.     case Alignment of
  354.       taLeftJustify  : Left := ARect.Left + DX;
  355.       taRightJustify : Left := ARect.Right - ACanvas.TextWidth(Text) - 3;
  356.     else { taCenter }
  357.       Left := ARect.Left + (ARect.Right - ARect.Left) shr 1
  358.               - (ACanvas.TextWidth(Text) shr 1);
  359.     end;
  360.     ExtTextOut(ACanvas.Handle, Left, ARect.Top + DY, ETO_OPAQUE or
  361.       ETO_CLIPPED, @ARect, PChar(Text), Length(Text), nil);
  362.   end
  363.   else begin                  { Use FillRect and Drawtext for dithered colors }
  364.     with DrawBitmap, ARect do { Use offscreen bitmap to eliminate flicker and }
  365.     begin                     { brush origin tics in painting / scrolling.    }
  366.       Width := Max(Width, Right - Left);
  367.       Height := Max(Height, Bottom - Top);
  368.       R := Rect(DX, DY, Right - Left - 1, Bottom - Top - 1);
  369.       B := Rect(0, 0, Right - Left, Bottom - Top);
  370.     end;
  371.     with DrawBitmap.Canvas do
  372.     begin
  373.       Font := ACanvas.Font;
  374.       Font.Color := ACanvas.Font.Color;
  375.       Brush := ACanvas.Brush;
  376.       Brush.Style := bsSolid;
  377.       FillRect(B);
  378.       SetBkMode(Handle, TRANSPARENT);
  379.       DrawText(Handle, PChar(Text), Length(Text), R, AlignFlags[Alignment]);
  380.     end;
  381.     ACanvas.CopyRect(ARect, DrawBitmap.Canvas, B);
  382.   end;
  383. end;
  384.  
  385. constructor TCustomDecisionGrid.Create(AOwner: TComponent);
  386. var
  387.   BmpId: BitmapId;
  388.   Bmp: TBitmap;
  389. begin
  390.   inherited Create(AOwner);
  391.   inherited BorderStyle := bsSingle;
  392.   inherited Options := [goDrawFocusSelected,goTabs, goRangeSelect,
  393.                         goColSizing, goRowSizing];
  394.   inherited DefaultDrawing := True;
  395.   ScrollBars := ssBoth;
  396.   FOptions := [cgGridLines, cgOutliner, cgPivotable];
  397.   FGridStateX := csNormal;
  398.   FDataLink := TDecisionGridDataLink.Create(Self);
  399.   FDataLink.FGrid := Self;
  400.   Color := clBtnFace;
  401.   ParentColor := False;
  402.   FLabelFont := TFont.Create;
  403.   FLabelFont.OnChange := FontChanged;
  404.   FLabelColor := clBtnFace;
  405.   FLabelSumColor := clInactiveCaption;
  406.   FCaptionFont := TFont.Create;
  407.   FCaptionColor := clActiveCaption;
  408.   FCaptionFont.Color := clCaptionText;
  409.   FCaptionFont.OnChange := FontChanged;
  410.   FDataFont := TFont.Create;
  411.   FDataFont.OnChange := FontChanged;
  412.   FDataColor := clInfoBk;
  413.   FDataSumColor := clNone;
  414.   SetColWidth(100);            { default column width }
  415.   SetRowHeight(20);
  416.   FGridLineColor := clWindowText;
  417.   FGridLineWidth := 1;
  418.   FShowCubeEditor := false;
  419.   FSaveCellExtents := False;
  420.   FDisplayDims := TDisplayDims.Create(self, TDisplayDim);
  421.   FChanging := False;
  422.   NewDataStructure;                    { to initialize the dimension information }
  423.   HideEditor;
  424.   Bmp := TBitmap.Create;
  425.   FMenu := TQuickMenu.Create(self);
  426.   FActiveGrid := false;
  427.   inherited FixedCols := 0;
  428.   inherited FixedRows := 0;
  429.   inherited RowCount := 1;
  430.   inherited ColCount := 1;
  431.   { Initialize Decision data structure }
  432.   try
  433.     FIndicators := TImageList.CreateSize(15, 15);
  434.     for BmpId := Low(BitmapId) to High(BitmapId) do
  435.     begin
  436.       Bmp.Handle := LoadBitmap(HInstance, PChar(BitmapArray[BmpId]));
  437.       FIndicators.AddMasked(Bmp, clMaroon);
  438.     end;
  439.   finally
  440.     Bmp.Free;
  441.   end;
  442.   UsesBitmap;
  443.   RCS;
  444. end;
  445.  
  446. destructor TCustomDecisionGrid.Destroy;
  447. begin
  448.   FIndicators.Free;
  449.   FIndicators := nil;
  450.   FDataLink.Free;
  451.   FDataLink := nil;
  452.   FLabelFont.Free;
  453.   FLabelFont := nil;
  454.   FCaptionFont.Free;
  455.   FCaptionFont := nil;
  456.   FDataFont.Free;
  457.   FDataFont := nil;
  458.   FDisplayDims.Clear;
  459.   FDisplayDims.Free;
  460.   FMenu.Free;
  461.   FMenu := nil;
  462.   inherited Destroy;
  463.   ReleaseBitmap;
  464. end;
  465.  
  466. procedure TCustomDecisionGrid.Notification(AComponent: TComponent; Operation: TOperation);
  467. begin
  468.   inherited;
  469.   if (AComponent is TPivotButton) and (Operation = opInsert) then
  470.   begin
  471.     if assigned(DecisionSource) then
  472.       TPivotButton(AComponent).DecisionSource := DecisionSource;
  473.   end;
  474. end;
  475.  
  476. {Translate the raw grid X,Y coordinate into cell positions in the cross tab}
  477. procedure TCustomDecisionGrid.RawToDataCoord(var X,Y: LongInt);
  478. begin
  479.   Dec(X, fColOffset);
  480.   Dec(X, FCaptionCol);
  481.   Dec(Y, FRowOffset);
  482.   Dec(Y, FCaptionRow);
  483. end;
  484.  
  485. {Translate the cell coordinates in the Decision to raw positions in the grid}
  486. procedure TCustomDecisionGrid.DataToRawCoord(var X,Y: LongInt);
  487. begin
  488.   Inc(X, fColOffset);
  489.   Inc(X, FCaptionCol);
  490.   Inc(Y, FRowOffset);
  491.   Inc(Y, FCaptionRow);
  492. end;
  493.  
  494. function TCustomDecisionGrid.DataToRawX(X: LongInt): LongInt;
  495. begin
  496.   Result := X + FColOffset + FCaptionCol;
  497. end;
  498.  
  499. function TCustomDecisionGrid.DataToRawY(Y: LongInt): LongInt;
  500. begin
  501.   Result := Y + FRowOffset + FCaptionRow;
  502. end;
  503.  
  504. {
  505.   These routines should be called only when the number of dimensions
  506.   could have changed (i.e., when the data cube has been attached or
  507.   detached, on initialization, or when the data cube goes active).
  508.   By convention, the data cube is attached or detached at those times.
  509. }
  510. procedure TCustomDecisionGrid.NewDataStructure;
  511. var
  512.   i: Integer;
  513.   X: TDisplayDim;
  514.   bCreating: boolean;
  515. begin
  516.   if assigned(DecisionSource) and DecisionSource.Ready then
  517.     with DecisionSource do
  518.     begin
  519.       FDisplayDims.bQuiet := true;
  520.       {
  521.         For now, do a simple test to see if the number of dimensions has changed.
  522.         if not, we can assume that the datasource is the some as before and use
  523.         the old FDisplayDims.  Eventually, some code which is resistant to
  524.         datasource restructures would be good.
  525.       }
  526.       bCreating := not (FDisplayDims.count = (nDims+nSums));
  527.       if bCreating then FDisplayDims.Clear;
  528.       for i := 0 to nDims-1 do
  529.       begin
  530.         if bCreating then FDisplayDims.Add;
  531.         X := FDisplayDims[i];
  532.         if (X.FieldName <> DecisionSource.GetDimensionName(i)) then
  533.           X.FFieldName := DecisionSource.GetDimensionName(i);
  534.       end;
  535.       for i := 0 to nSums-1 do
  536.       begin
  537.         if bCreating then FDisplayDims.Add;
  538.         X := FDisplayDims[i + nDims];
  539.         if (X.FieldName <> DecisionSource.GetSummaryName(i)) then
  540.           X.FFieldName := DecisionSource.GetSummaryName(i);
  541.       end;
  542.       FDisplayDims.bQuiet := false;
  543.     end;
  544.   NewGridLayout;
  545. end;
  546.  
  547.   { NewGridLayout:  assumes that the FDecisionData has been set up }
  548.  
  549. procedure TCustomDecisionGrid.NewGridLayout;
  550. var
  551.   i: Integer;
  552. begin
  553.   if assigned(DecisionSource) and DecisionSource.Ready then
  554.   begin
  555.     with DecisionSource do
  556.     begin
  557.       FRowOffset := DecisionSource.nOpenColDims;
  558.       fColOffset := DecisionSource.nOpenRowDims;
  559.       FActRows := DecisionSource.nOpenRowDims;
  560.       FActCols := DecisionSource.nOpenColDims;
  561.       FTotRows := DecisionSource.nRowDims;
  562.       FTotCols := DecisionSource.nColDims;
  563.       FCaptionCol := 0;
  564.       if ((FActCols = 0) and (FTotCols > 0)) then
  565.         FCaptionRow := 2
  566.       else
  567.         FCaptionRow := 1;
  568.       if cgOutliner in Options then
  569.         FCaptionCol := FCaptionCol + 1;
  570.       inherited FixedCols := 0;
  571.       inherited FixedRows := 0;
  572.       inherited RowCount := FRowOffset + FCaptionRow + DecisionSource.nDataRows;
  573.       inherited ColCount := fColOffset + FCaptionCol + DecisionSource.nDataCols;
  574.       if (DecisionSource.nDataRows > 0) then
  575.         inherited FixedCols := fColOffset+FCaptionCol;
  576.       if (DecisionSource.nDataCols > 0) then
  577.         inherited FixedRows := FRowOffset + FCaptionRow;
  578.       FActiveGrid := true;
  579.       InitializeGridCells;
  580.     end;
  581.   end
  582.   else
  583.   begin
  584.     if FActiveGrid then
  585.     begin
  586.       FActiveGrid := false;
  587.       inherited FixedCols := 0;
  588.       inherited FixedRows := 0;
  589.       inherited RowCount := 1;
  590.       inherited ColCount := 1;
  591.     end;
  592.     FRowOffset := 0;
  593.     fColOffset := 0;
  594.     FActRows := 0;
  595.     FActCols := 0;
  596.     FTotRows := 0;
  597.     FTotCols := 0;
  598.     FCaptionCol := 0;
  599.     FCaptionRow := 0;
  600.   end;
  601.   { Call any buttons we contain to tell them it is time to initialize }
  602.   for i := 0 to ControlCount-1 do
  603.   begin
  604.     if Controls[i] is TPivotButton then
  605.       TPivotButton(Controls[i]).NewState;
  606.   end;
  607. end;
  608.  
  609. procedure TCustomDecisionGrid.InitializeGridCells;
  610. var
  611.   i,j: Integer;
  612.   isBreak, isSum: boolean;
  613.   iDim: Integer;
  614. begin
  615.   if assigned(DecisionSource) and assigned(FDisplayDims) then
  616.   begin
  617.     FChanging := True;
  618.     if cgOutliner in Options then colWidths[0] := PlusWidth;
  619.     for i := FCaptionCol to ColCount-1 do
  620.       colWidths[i] := colWidth;
  621.     for i := FCaptionRow to RowCount-1 do
  622.       rowHeights[i] := rowHeight;
  623.     for i := 0 to FActRows-1 do
  624.     begin
  625.       iDim :=  DecisionSource.GetActiveDim(dgRow,i,true);
  626.       if (not FDisplayDims[iDim].FSubs) then
  627.       begin
  628.         for j := 0 to RowCount-FixedRows-1 do
  629.         begin
  630.           DecisionSource.GetValueIndex(dgRow,i,j,isBreak,isSum);
  631.           if isBreak and isSum then RowHeights[FixedRows + j] := NoSpace;
  632.         end;
  633.       end;
  634.     end;
  635.     for i := 0 to FActCols-1 do
  636.     begin
  637.       iDim :=  DecisionSource.GetActiveDim(dgCol,i,true);
  638.       if (not FDisplayDims[iDim].FSubs) then
  639.       begin
  640.         for j := 0 to ColCount-FixedCols-1 do
  641.         begin
  642.           DecisionSource.GetValueIndex(dgCol,i,j,isBreak,isSum);
  643.           if isBreak and isSum then ColWidths[FixedCols + j] := NoSpace;
  644.         end;
  645.       end;
  646.     end;
  647.     FChanging := False;
  648.   end;
  649. end;
  650.  
  651. {
  652.   These are internal routines to service external hooks.
  653.   These are used to drive the grid through an external pivot,
  654.   and are not used any more.
  655. }
  656.  
  657. procedure TCustomDecisionGrid.GetHitTypes(ARow,AColumn: Integer;
  658.                                           var ValueIndex: Integer;
  659.                                           var DrawState: TDecisionDrawState;
  660.                                           var CellType: TDecisionCellType);
  661. var
  662.   IDim: Integer;
  663.   isSum, isBreak: Boolean;
  664.   aRowState: TRowState;
  665.   aState: TDimState;
  666.   Coord: TGridCoord;
  667.   iRange: TDimRange;
  668.   i, rawRow, rawCol: Integer;
  669. begin
  670.   DrawState := [];
  671.   Coord.X := AColumn;
  672.   Coord.Y := ARow;
  673.   CellType := WhichCoord(Coord);
  674.   if assigned(DecisionSource) then
  675.     with DecisionSource do
  676.       case CellType of
  677.         ctData:
  678.         begin
  679.           DrawState := [dsData];
  680.         end;
  681.         ctCaptionCol:
  682.         begin
  683.           DrawState := [dsColCaption];
  684.           if (cgOutliner in Options) then
  685.           begin
  686.             iDim := DecisionSource.GetActiveDim(dgCol, AColumn,true);
  687.             aRowState := DecisionSource.GetRowState(iDim);
  688.             if (rcNextClosed in aRowState) then
  689.               DrawState := DrawState + [dsOpenAfter]
  690.             else if (rcNextOpen in aRowState) then
  691.               DrawState := DrawState + [dsCloseAfter];
  692.           end;
  693.         end;
  694.         ctCaptionRow:
  695.         begin
  696.           DrawState := [dsRowCaption];
  697.           if (cgOutliner in Options) then
  698.           begin
  699.             iDim := DecisionSource.GetActiveDim(dgRow,AColumn+fColOffset,true);
  700.             aRowState := GetRowState(iDim);
  701.             if (rcNextClosed in aRowState) then
  702.               DrawState := DrawState + [dsOpenAfter]
  703.             else if (rcNextOpen in aRowState) then
  704.               DrawState := DrawState + [dsCloseAfter];
  705.           end;
  706.         end;
  707.         ctColLabel:
  708.         begin
  709.           ValueIndex := DecisionSource.GetValueIndex(dgCol,ARow+FRowOffset,AColumn,isBreak,isSum);
  710.           DrawState := [dsColValue];
  711.           if isSum then
  712.           begin
  713.             DrawState := DrawState + [dsSum];
  714.           end;
  715.           if isBreak then
  716.           begin
  717.             DrawState := DrawState + [dsGroupStart];
  718.           end
  719.           else    { not on a break, then see }
  720.           begin
  721.             rawCol := DataToRawX(AColumn);
  722.             if (rawCol > 0) and (colWidths[rawCol-1] = NoSpace) then
  723.             begin
  724.               iRange :=  DecisionSource.GetGroupExtent(dgCol, ARow+FRowOffset, AColumn);
  725.               iRange.First := DataToRawX(iRange.First);
  726.               DrawState := DrawState + [dsGroupStart];
  727.               for i := iRange.First to rawCol-1 do
  728.                 if (colWidths[i] > NoSpace) then
  729.                   DrawState := DrawState - [dsGroupStart];
  730.             end;
  731.           end;
  732.         end;
  733.         ctRowLabel:
  734.         begin
  735.           DrawState := [dsRowValue];
  736.           ValueIndex := DecisionSource.GetValueIndex(dgRow,AColumn + fColOffset,ARow,isBreak,isSum);
  737.           if isSum then
  738.           begin
  739.             DrawState := DrawState + [dsSum];
  740.           end;
  741.           if isBreak then
  742.           begin
  743.             DrawState := DrawState + [dsGroupStart];
  744.           end
  745.           else
  746.           begin
  747.             rawRow := DataToRawY(ARow);
  748.             if (rawRow > 0) and (rowHeights[rawRow-1] = NoSpace) then
  749.             begin
  750.               iRange := DecisionSOurce.GetGroupExtent(dgRow, AColumn+FColOffset, ARow);
  751.               iRange.First := DataToRawY(iRange.First);
  752.               DrawState := DrawState + [dsGroupStart];
  753.               for i := iRange.First to rawRow-1 do
  754.                 if (rowHeights[i] > NoSpace) then
  755.                   DrawState := DrawState - [dsGroupStart];
  756.             end;
  757.           end;
  758.         end;
  759.         ctRowIndicator: DrawState := [dsRowIndicator];
  760.         ctColIndicator: DrawState := [dsColIndicator];
  761.         ctRowPlus:
  762.         begin
  763.           DrawState := [dsRowPlus];
  764.           i := DecisionSource.GetActiveDim(dgRow, 0, false);
  765.           if (i >= 0) and (cgOutliner in Options) then
  766.           begin
  767.             aRowState := GetRowState(i);
  768.             aState := GetState(i);
  769.             if (aState = dmClosed) then
  770.               DrawState := DrawState + [dsOpenAfter]
  771.             else if (aState = dmOpen) then
  772.               DrawState := DrawState + [dsCloseAfter];
  773.           end;
  774.         end;
  775.         ctColPlus:
  776.         begin
  777.             DrawState := [dsColPlus];
  778.           i := DecisionSource.GetActiveDim(dgCol, 0, false);
  779.           if (i >= 0) and (cgOutliner in Options) then
  780.           begin
  781.             aRowState := GetRowState(i);
  782.             aState := GetState(i);
  783.             if (aState = dmClosed) then
  784.               DrawState := DrawState + [dsOpenAfter]
  785.             else if (aState = dmOpen) then
  786.               DrawState := DrawState + [dsCloseAfter];
  787.           end;
  788.         end;
  789.         ctNone:
  790.         begin
  791.             DrawState := [dsNone];
  792.         end;
  793.       end;
  794. end;
  795.  
  796. function TCustomDecisionGrid.GetSpecialState(ARow,AColumn: Integer): TDecisionPivotState;
  797. begin
  798.   Result := psNone;
  799.   case FGridStateX of
  800.     csPivoting:
  801.       if (FTargetCell.Y = ARow) then
  802.       begin
  803.         if FTargetSwitch then
  804.         begin
  805.           if (FTargetCell.X = AColumn) then Result := psMiddlePivot;
  806.         end
  807.         else if (FTargetCell.X > FActCols) then
  808.         begin
  809.           if (FTargetCell.X - 1 = AColumn) then Result := psTopPivot;
  810.         end
  811.         else if (FTargetCell.X = AColumn) then
  812.           Result := psLeftPivot
  813.         else if (FTargetCell.X - 1 = AColumn) then
  814.           Result := psRightPivot;
  815.       end;
  816.   end;
  817. end;
  818.  
  819. {
  820.   Fetches data values for the grid, including the row and column
  821.   labels and captions corresponding to dimension data values.
  822. }
  823.  
  824. function TCustomDecisionGrid.GetDataPoint(ARow,AColumn: LongInt;
  825.                                           var State: TDecisionDrawState;
  826.                                           var Alignment: TAlignment): String;
  827.  
  828. var
  829.   aCellType: TDecisionCellType;
  830.   ValueIndex, SubLevel: Integer;
  831. begin
  832.   State := [];
  833.   Result := '';
  834.   Alignment := taCenter;
  835.   if assigned(DecisionSource) then
  836.     with DecisionSource do
  837.     begin
  838.       GetHitTypes(ARow,AColumn,ValueIndex,State,aCellType);
  839.       case aCellType of
  840.         ctData:
  841.         begin
  842.           Result := GetData(Arow, AColumn, SubLevel);
  843.           if (SubLevel > 0) then State := State + [dsSum];
  844.        end;
  845.         ctCaptionCol:
  846.       begin
  847.           Result := GetCaption(dgCol, AColumn);
  848.         end;
  849.     ctCaptionRow:
  850.         begin
  851.          Result := GetCaption(dgRow, AColumn+FcolOffset);
  852.         end;
  853.     ctColLabel:
  854.         begin
  855.            if dsGroupStart in State then
  856.           begin
  857.             if (dsSum in State) then
  858.             begin
  859.               Result := sTotalCaption;
  860.             end
  861.             else
  862.             begin
  863.               Result := GetLabel(dgCol, ARow + FRowOffset ,ValueIndex);
  864.             end;
  865.           end;
  866.         end;
  867.         ctRowLabel:
  868.         begin
  869.            if (dsGroupStart in State) then
  870.           begin
  871.             if (dsSum in State) then
  872.             begin
  873.               Result := sTotalCaption;
  874.             end
  875.             else
  876.             begin
  877.               Result := GetLabel(dgRow, AColumn+FColOffset,ValueIndex);
  878.             end;
  879.           end;
  880.         end;
  881.       end;
  882.     end;
  883. end;
  884.  
  885. procedure TCustomDecisionGrid.SetColWidth(Value: Integer);
  886. begin
  887.   FColWidth := Value;
  888.   inherited DefaultColWidth := Value;
  889.   NewGridLayout;
  890. end;
  891.  
  892. procedure TCustomDecisionGrid.SetRowHeight(Value: Integer);
  893. begin
  894.   if (FRowHeight <> Value) then
  895.   begin
  896.     FRowHeight := Value;
  897.     inherited DefaultRowHeight := Value;
  898.     Invalidate;
  899.   end;
  900. end;
  901.  
  902. procedure TCustomDecisionGrid.SetGridLineWidth(Value: Integer);
  903. begin
  904.   FGridLineWidth := Value;
  905.   Invalidate;
  906. end;
  907. procedure TCustomDecisionGrid.SetGridLineColor(Value: TColor);
  908. begin
  909.   FGridLineColor := Value;
  910.   Invalidate;
  911. end;
  912. procedure TCustomDecisionGrid.SetLabelFont(Value: TFont);
  913. begin
  914.   FLabelFont.Assign(Value);
  915.   Invalidate;
  916. end;
  917. procedure TCustomDecisionGrid.SetLabelColor(Value: TColor);
  918. begin
  919.   FLabelColor := Value;
  920.   Invalidate;
  921. end;
  922.  
  923. procedure TCustomDecisionGrid.SetLabelSumColor(Value: TColor);
  924. begin
  925.   FLabelSumColor := Value;
  926.   Invalidate;
  927. end;
  928.  
  929. procedure TCustomDecisionGrid.SetCaptionFont(Value: TFont);
  930. begin
  931.   FCaptionFont.Assign(Value);
  932.   Invalidate;
  933. end;
  934.  
  935. procedure TCustomDecisionGrid.SetCaptionColor(Value: TColor);
  936. begin
  937.   FCaptionColor := Value;
  938.   Invalidate; { Only invalidate captions ... }
  939. end;
  940.  
  941. procedure TCustomDecisionGrid.SetDataFont(Value: TFont);
  942. begin
  943.   FDataFont.Assign(Value);
  944.   Invalidate;
  945. end;
  946.  
  947. procedure TCustomDecisionGrid.SetDataColor(Value: TColor);
  948. begin
  949.   FDataColor := Value;
  950.   Invalidate;   { Only invalidate headers ... }
  951. end;
  952.  
  953. procedure TCustomDecisionGrid.SetDataSumColor(Value: TColor);
  954. begin
  955.   FDataSumColor := Value;
  956.   Invalidate;   { Only invalidate headers ... }
  957. end;
  958.  
  959. procedure TCustomDecisionGrid.FontChanged(Sender: TObject);
  960. begin
  961.   Invalidate;
  962. end;
  963.  
  964. procedure TCustomDecisionGrid.SetOptions(Value: TDecisionGridOptions);
  965. begin
  966.   if (FOptions <> Value) then
  967.   begin
  968.     FOptions := Value;
  969.     NewGridLayout;
  970.   end;
  971. end;
  972.  
  973. procedure TCustomDecisionGrid.DrawSpecialState(ACanvas: TCanvas; ARect: TRect;
  974.                                                DrawState: TDecisionDrawState;
  975.                                                PivotState: TDecisionPivotState);
  976. var
  977.   X, Y: Integer;
  978. begin
  979.   with ARect do
  980.   begin
  981.     if (dsOpenAfter in DrawState) then
  982.     begin
  983.       X := Right - FIndicators.Width;
  984.       Y := (Top + Bottom - FIndicators.Height) shr 1;
  985.       FIndicators.Draw(ACanvas, X, Y, Integer(biDOpen));
  986.     end;
  987.     if (dsCloseAfter in DrawState) then
  988.     begin
  989.       X := Right - FIndicators.Width;
  990.       Y := (Top + Bottom - FIndicators.Height) shr 1;
  991.       FIndicators.Draw(ACanvas, X, Y, Integer(biDClose));
  992.     end;
  993.     if (dsCloseBefore in DrawState) then
  994.     begin
  995.       X := Left;
  996.       Y := (Top + Bottom - FIndicators.Height) shr 1;
  997.       FIndicators.Draw(ACanvas, X, Y, Integer(biDClose));
  998.     end;
  999.     if (dsOpenBefore in DrawState) then
  1000.     begin
  1001.       X := Left;
  1002.       Y := (Top + Bottom - FIndicators.Height) shr 1;
  1003.       FIndicators.Draw(ACanvas, X, Y, Integer(biDOpen));
  1004.     end;
  1005.     if (PivotState = psLeftPivot) then
  1006.     begin
  1007.       Y := (Top + Bottom - FIndicators.Height) shr 1;
  1008.       FIndicators.Draw(ACanvas, Left, Y, Integer(biLeftArrow));
  1009.       ACanvas.Pen.Color := clRed;
  1010.       ACanvas.Pen.Width := 2;
  1011.       ACanvas.MoveTo(Left,Top);
  1012.       ACanvas.LineTo(Left,Bottom);
  1013.     end;
  1014.     if (PivotState = psRightPivot) then
  1015.     begin
  1016.       X := Right - FIndicators.Width;
  1017.       Y := (Top + Bottom - FIndicators.Height) shr 1;
  1018.       FIndicators.Draw(ACanvas, X, Y, Integer(biRightArrow));
  1019.     end;
  1020.     if (PivotState = psMiddlePivot) then
  1021.     begin
  1022.       X := (Left + Right - FIndicators.Width) div 2;
  1023.       Y := (Top + Bottom - FIndicators.Height) div 2;
  1024.       FIndicators.Draw(ACanvas, X, Y, Integer(biPivot));
  1025.     end;
  1026.     if (PivotState = psTopPivot) then
  1027.     begin
  1028.       ACanvas.Pen.Color := clRed;
  1029.       ACanvas.Pen.Width := 2;
  1030.       ACanvas.MoveTo(Left,Top+1);
  1031.       ACanvas.LineTo(Right,Top+1);
  1032.     end;
  1033.   end;
  1034. end;
  1035.  
  1036. function TCustomDecisionGrid.SelectCell(Arow, AColumn:LongInt): Boolean;
  1037. begin
  1038.   Result := True;
  1039. end;
  1040.  
  1041. procedure TCustomDecisionGrid.TopLeftChanged;
  1042. begin
  1043.   inherited TopLeftChanged;
  1044.   if Assigned(FOnTopLeftChanged) then FOnTopLeftChanged(Self);
  1045. end;
  1046.  
  1047. procedure TCustomDecisionGrid.ColWidthsChanged;
  1048. var
  1049.   i, newWidth: Integer;
  1050. begin
  1051.   {
  1052.     In design mode, permit only the first summary row to be modified in width
  1053.     Keep everything else to that size
  1054.   }
  1055.   if (csDesigning in ComponentState) and not FChanging then
  1056.   begin
  1057.     FChanging := true;
  1058.     NewWidth := FColWidth;
  1059.     for i := FCaptionCol+FActRows to ColCount-1 do
  1060.       if (ColWidths[i] > NoSpace) and (Colwidths[i] <> FColWidth) then
  1061.         NewWidth := Colwidths[i];
  1062.     for i := FCaptionCol+FActRows+1 to ColCount-1 do
  1063.     begin
  1064.       ColWidths[i] := NewWidth;
  1065.     end;
  1066.     SetColWidth(NewWidth);
  1067.     FChanging := False;
  1068.   end;
  1069. end;
  1070.  
  1071. procedure TCustomDecisionGrid.RowHeightsChanged;
  1072. var
  1073.   i: Integer;
  1074.   newHeight: Integer;
  1075. begin
  1076.   {
  1077.     In design mode, permit only the first summary row to be modified in width
  1078.     Keep everything else to that size
  1079.   }
  1080.   if (csDesigning in ComponentState) and not FCHanging then
  1081.   begin
  1082.     FChanging := True;
  1083.     NewHeight := FRowHeight;
  1084.     for i := 0 to RowCount - 1 do
  1085.     begin
  1086.       if (RowHeights[i] > NoSpace) and (RowHeights[i] <> FRowHeight) then
  1087.         NewHeight := RowHeights[i];
  1088.     end;
  1089.     for i := 0 to RowCount-1 do
  1090.       RowHeights[i] := NewHeight;
  1091.     SetRowHeight(NewHeight);
  1092.     FChanging := False;
  1093.   end;
  1094. end;
  1095.  
  1096. function TCustomDecisionGrid.CellRect(ACol, ARow: Longint): TRect;
  1097. begin
  1098.   Result := BoxRect(ACol+FixedCols, ARow+FixedRows, ACol+FixedCols, ARow+FixedRows);
  1099. end;
  1100.  
  1101. procedure TCustomDecisionGrid.Paint;
  1102. var
  1103.   Rect: TRect;
  1104. begin
  1105.   inherited;
  1106.   if not (assigned(DecisionSource) and DecisionSource.Ready and factivegrid) then
  1107.     Exit;
  1108.   Rect :=  BoxRect(0, 0, ColCount, RowCount);
  1109.   if (cgGridLines in Options) and (GridLineWidth > 0) then
  1110.     with Canvas do
  1111.     begin
  1112.       Pen.Color := FGridLineColor;
  1113.       Pen.Width := FGridLineWidth;
  1114.       with Rect do
  1115.       begin
  1116.         MoveTo(Right, Top-1);
  1117.         LineTo(Right, Bottom);
  1118.         LineTo(Left-1, Bottom);
  1119.         if (BorderStyle = bsNone) and not (cgOutliner in Options) then
  1120.         begin
  1121.           MoveTo(Left,Bottom);
  1122.           LineTo(Left,Top);
  1123.         end;
  1124.       end;
  1125.     end;
  1126. end;
  1127.  
  1128. procedure TCustomDecisionGrid.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
  1129. var
  1130.   Value: string;
  1131.   x: integer;
  1132.   FrameOffs: Byte;
  1133.   Elevated: Boolean;
  1134.   DrawState: TDecisionDrawState;
  1135.   PivotState: TDecisionPivotState;
  1136.   Specials: TDecisionDrawState;
  1137.   Alignment: TAlignment;
  1138.   aColor: TColor;
  1139.   aFont: TFont;
  1140.   aDisplayDim: TDisplayDim;
  1141. begin
  1142.   if not (assigned(DecisionSource) and DecisionSource.Ready and factivegrid) then
  1143.     Exit;
  1144.   if (csLoading in ComponentState) then
  1145.   begin
  1146.     Canvas.Brush.Color := Color;
  1147.     Canvas.FillRect(ARect);
  1148.     Exit;
  1149.   end;
  1150.   if (rowHeights[ARow] <= NoSpace) or (colWidths[ACol] <= NoSpace) then
  1151.     Exit;
  1152.   RawToDataCoord(ACol,ARow);
  1153.   aDisplayDim := nil;
  1154.  
  1155.   with Canvas do
  1156.   begin
  1157.     { Elevate applies to either }
  1158.     Value := GetDataPoint(ARow,ACol,DrawState,Alignment);
  1159.     Elevated := (gdFixed in AState) and (cgGridLines in Options) and
  1160.             ([dsRowCaption,dsRowIndicator,dsColCaption,dsRowPlus,dsColPlus,dsNone] * DrawState <> []);
  1161.     if (gdFocused in AState) then
  1162.     begin
  1163.       Brush.Color := clHighlight;
  1164.       Font.Color := clHighlightText;
  1165.     end
  1166.     else if (gdFixed in AState) then
  1167.     begin
  1168.       if [dsRowIndicator, dsNone, dsColPlus, dsColIndicator]*DrawState <> [] then
  1169.       begin
  1170.         Brush.Color := Color;
  1171.       end
  1172.       else if (dsRowCaption in DrawState) or (dsColCaption in DrawState) then
  1173.       begin
  1174.         Font := FCaptionFont;
  1175.         Brush.Color := FCaptionColor;
  1176.       end
  1177.       else if (dsRowValue in DrawState) then
  1178.       begin
  1179.         Font := FLabelFont;
  1180.         Brush.Color := FLabelColor;
  1181.         if assigned(FDisplayDims) and assigned(DecisionSource) then
  1182.         begin
  1183.           aDisplayDim  := TDisplayDim(FDisplayDims[DecisionSource.GetActiveDim(dgRow, FActRows+ACol,true)]);
  1184.           if (aDisplayDim.FColor <> clNone) then
  1185.             Brush.Color := aDisplayDim.FColor;
  1186.           Alignment := aDisplayDim.FAlignment;
  1187.         end;
  1188.         if (dsSum in DrawState) then
  1189.         begin
  1190.           if (FLabelSumColor <> clNone) then
  1191.             Brush.Color := FLabelSumColor;
  1192.         end;
  1193.       end
  1194.       else if (dsColValue in DrawState) then
  1195.       begin
  1196.         Font := FLabelFont;
  1197.         Brush.Color := FLabelColor;
  1198.         if assigned(FDisplayDims) and assigned(DecisionSource) then
  1199.         begin
  1200.           aDisplayDim  := TDisplayDim(FDisplayDims[DecisionSource.GetActiveDim(dgCol, FActCols+ARow,true)]);
  1201.           if (aDisplayDim.FColor <> clNone) then Brush.Color := aDisplayDim.FColor;
  1202.           Alignment := aDisplayDim.FAlignment;
  1203.         end;
  1204.         if (dsSum in DrawState) then
  1205.         begin
  1206.           if (FLabelSumColor <> clNone) then
  1207.             Brush.Color := FLabelSumColor;
  1208.         end;
  1209.       end
  1210.       else
  1211.       begin
  1212.         Font := Self.Font;
  1213.         Brush.Color := Self.Color;
  1214.       end;
  1215.     end
  1216.     else
  1217.     begin
  1218.       Font := FDataFont;
  1219.       Brush.Color := FDataColor;
  1220.       if Assigned(FDisplayDims) and Assigned(DecisionSource) then
  1221.       begin
  1222.         aDisplayDim := TDisplayDim(FDisplayDims[DecisionSource.nDims + DecisionSource.CurrentSum]);
  1223.         Alignment := aDisplayDim.FAlignment;
  1224.       end;
  1225.       if (dsSum in DrawState) then
  1226.       begin
  1227.         if FDataSumColor <> clNone then Brush.Color := FDataSumColor;
  1228.       end
  1229.       else if Assigned(aDisplayDim) and (aDisplayDim.FColor <> clNone) then
  1230.         Brush.Color := aDisplayDim.FColor;
  1231.     end;
  1232.     if not Elevated then
  1233.       FrameOffs := 2
  1234.     else
  1235.     begin
  1236.       InflateRect(ARect, -1, -1);
  1237.       FrameOffs := 1;
  1238.     end;
  1239.     if assigned(FOnDecisionDrawCell) then
  1240.     begin
  1241.       aFont := Font;
  1242.       aColor := Brush.Color;
  1243.       FOnDecisionDrawCell(Self, ACol, ARow, Value, aFont, aColor, AState, DrawState);
  1244.       Font := aFont;
  1245.       Brush.Color := aColor;
  1246.       if not DefaultDrawing then Exit;
  1247.     end;
  1248.     if (Value = '') then
  1249.       FillRect(ARect)
  1250.     else
  1251.       if ((dsRowCaption in DrawState) or (dsColCaption in DrawState)) and (dsOpenAfter in DrawState) or (dsCloseAfter in DrawState) then
  1252.       begin
  1253.         FillRect(ARect);
  1254.         ARect.Right := ARect.Right-FIndicators.Width;
  1255.         if TextWidth(Value) > (ARect.Right-ARect.Left) then
  1256.           Alignment := taLeftJustify;
  1257.         WriteText(Canvas, ARect, FrameOffs, FrameOffs, Value, Alignment);
  1258.         ARect.Right := ARect.Right+FIndicators.Width;
  1259.       end
  1260.       else
  1261.       begin
  1262.         if TextWidth(Value) > (ARect.Right-ARect.Left) then
  1263.           Alignment := taLeftJustify;
  1264.         WriteText(Canvas, ARect, FrameOffs, FrameOffs, Value, Alignment);
  1265.       end;
  1266.     Pen.Color := FGridLineColor;
  1267.     Pen.Width := FGridLineWidth;
  1268.     { drawlines }
  1269.     if ([dsSum, dsData, dsRowValue, dsColValue]*DrawState <> [])
  1270.     and (FGridLineWidth > 0) and (cgGridLines in Options) then
  1271.     begin
  1272.       MoveTo(ARect.Left, ARect.Bottom);
  1273.       { draw the left border }
  1274.       if ((aCol = -FActRows) or ((dsColValue in DrawState) and ([dsGroupStart,dsSum]*DrawState = []))) then
  1275.         MoveTo(ARect.Left, ARect.Top)
  1276.       else
  1277.       begin
  1278.         LineTo(ARect.Left, ARect.Top-1);
  1279.         MoveTo(Arect.Left, Arect.Top);
  1280.       end;
  1281.       { draw the top border }
  1282.       if (((dsRowValue in DrawState) and ([dsGroupStart,dsSum]*DrawState = []))) then
  1283.         MoveTo(ARect.Right, ARect.Top)
  1284.       else
  1285.         LineTo(ARect.Right, ARect.Top);
  1286.       { draw the right border }
  1287.       if (((aCol <> colCount-FixedCols-1) and ([dsGroupStart,dsSum]*DrawState = []))) then
  1288.         MoveTo(ARect.Right, ARect.Bottom)
  1289.       else
  1290.       begin
  1291.         MoveTo(ARect.Right, ARect.Top-1);
  1292.         LineTo(ARect.Right, ARect.Bottom);
  1293.       end;
  1294.       { draw the BOTTOM border }
  1295.       if ((aRow = RowCount-FixedRows-1) or ([dsGroupStart,dsSum]*DrawState <> [])) then
  1296.         LineTo(ARect.Left, ARect.Bottom);
  1297.     end;
  1298.     if [dsRowPlus,dsColPlus] * DrawState <> [] then
  1299.     begin
  1300.       if (ARect.Left < (ARect.Right-PlusWidth)) and Elevated then
  1301.       begin
  1302.         x := ARect.Right;
  1303.         ARect.Right := ARect.Right-PlusWidth;
  1304.         InflateRect(ARect, 1, 1);
  1305.         DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_BOTTOMRIGHT);
  1306.         DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_TOPLEFT);
  1307.         InflateRect(ARect, -1, -1);
  1308.         ARect.Right := x;
  1309.       end;
  1310.       ARect.Left := ARect.Right-PlusWidth;
  1311.       Font := FCaptionFont;
  1312.       Brush.Color := FCaptionColor;
  1313.       FillRect(ARect);
  1314.     end;
  1315.     if Elevated then
  1316.     begin
  1317.       InflateRect(ARect, 1, 1);
  1318.       DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_BOTTOMRIGHT);
  1319.       DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_TOPLEFT);
  1320.       InflateRect(ARect, -1, -1);
  1321.     end;
  1322.     Specials := [dsOpenAfter,dsOpenBefore,dsCloseBefore,dsCloseAfter,dsRowPlus,dsColPlus];
  1323.     PivotState := GetSpecialState(ARow, ACol);
  1324.     if (DrawState * Specials <> []) or (PivotState <> psNone) then
  1325.       DrawSpecialState(Canvas, ARect, DrawState, PivotState);
  1326.   end;
  1327. end;
  1328.  
  1329. {check to see if the coordinate passed in is in the caption row, caption column,
  1330.  or the header.  Set Result to one of the values in the }
  1331.  
  1332. function TCustomDecisionGrid.WhichCoord( Coord: TGridCoord ): TDecisionCellType;
  1333. begin
  1334.   Result := ctNone;
  1335.   with Coord do
  1336.   begin
  1337.     if (X >= 0) and (Y >= 0) then
  1338.       Result := ctData
  1339.       { this is one of the row dimension names }
  1340.     else if (FActRows > 0) and (Y = -1) and (X < 0) and (x >= -FActRows) then
  1341.       Result := ctCaptionRow
  1342.       { this is one of the col dimension names }
  1343.     else if (FActCols > 0) and (Y = -FRowOffset-1) and (X >= 0) and (X < FActCols) then
  1344.       Result := ctCaptionCol
  1345.       { this is a row field vale }
  1346.     else if (Y >= 0) and (X < 0) and (X >= -FColOffset) then
  1347.       Result := ctRowLabel
  1348.       { this is a column field value }
  1349.     else if (X >= 0) and (Y < 0) and (Y > -FRowOffset-1) then
  1350.       Result := ctColLabel
  1351.     else if ((cgOutliner in Options) and (FTotCols > 0) and (((FActCols > 0) and (Y = -FActCols-1) and
  1352.     (X = -1)) or ((X = -1) and (Y = -2) and (FActCols = 0)))) then
  1353.       Result := ctColPlus
  1354.     else if ((cgOutliner in Options) and (FTotRows > 0) and (X = -FColOffset-FCaptionCol) and (Y = -1)) then
  1355.       Result := ctRowPlus
  1356.     else if ((cgOutliner in Options) and (X = -fColOffset-FCaptionCol)) then
  1357.       Result := ctRowIndicator;
  1358.   end;
  1359. end;
  1360.  
  1361.   {Function:    this performs the same function when in the middle of a pivot }
  1362.  
  1363. function TCustomDecisionGrid.WhichCoordExCap(Coord: TGridCoord): TDecisionCellType;
  1364. begin
  1365.   Result := ctNone;
  1366.   with Coord do
  1367.   begin
  1368.     if (Y = -1-FRowOffset) and (X = -fColOffset) and (FActCols > 0) and (FActRows > 0) then
  1369.       Result := ctNone { ctHeader }
  1370.     else if (Y = -1) and (X <= 0) then
  1371.       Result := ctCaptionRow
  1372.     else if (Y = -FRowOffset-1) and (X >= 0) and (X <= FActCols) then
  1373.       Result := ctCaptionCol
  1374.     else if (Y = -1) and (X = 1) and (FActCols = 0) then
  1375.       Result := ctNewCaptionCol;
  1376.   end;
  1377. end;
  1378.  
  1379. {Translate a mouse coordinate X,Y into a Decision cell position}
  1380.  
  1381. function TCustomDecisionGrid.MouseToDataCoord(X,Y: Integer): TGridCoord;
  1382. begin
  1383.   Result := MouseCoord(X,Y);
  1384.   if Result.X = -1 then
  1385.   begin
  1386.     Result.X := -1000;
  1387.     Exit;
  1388.   end;
  1389.   RawToDataCoord(Result.X,Result.Y);
  1390. end;
  1391.  
  1392. procedure TCustomDecisionGrid.InvalidateTargetCell;
  1393. var
  1394.   X, Y: LongInt;
  1395. begin
  1396.   X := FTargetCell.X;
  1397.   Y := FTargetCell.Y;
  1398.   DataToRawCoord(X, Y);
  1399.   InvalidateCell(X, Y);
  1400.   InvalidateCell(X-1, Y);
  1401. end;
  1402.   { This routine figures out whether the mouse is }
  1403. function TCustomDecisionGrid.GetHorzButtonPlace(X,Y: Integer): TButtonPlace;
  1404. var
  1405.   Coord, Coord2, Coord3: TGridCoord;
  1406.   Width: Integer;
  1407. begin
  1408.   Coord := MouseCoord(X,Y);                { grid coordinates where mouse is. }
  1409.   Width := ColWidths[Coord.X] div 4;
  1410.   Coord2 := MouseCoord(X-Width,Y);         { grid coordinate 1/4 col to left }
  1411.   Coord3 := MouseCoord(X+Width,Y);         { grid coordinate 1/4 col to right }
  1412.   if (Coord.X = -1) then Coord.X := ColCount;
  1413.   if (Coord3.X = -1) then Coord3.X := ColCount;
  1414.   {
  1415.     Set result to left if we are in the left quarter or the left column
  1416.     Set result to right if we are in the right quarter
  1417.     Else set result to middle.
  1418.   }
  1419.   if (Coord2.X < Coord.X) or ((Coord.X = 0) and (X <= Width)) then
  1420.     Result := bpLeft
  1421.   else if (Coord3.X > Coord.X) then
  1422.     Result := bpRight
  1423.   else
  1424.     Result := bpMiddle;
  1425. end;
  1426.  
  1427. {
  1428.   This routine is used when the user is in the middle of a pivot.  The mouse
  1429.   coordinates passed in are used to deduce whether the user is over a target
  1430.   zone.  If so, the appropriate
  1431. }
  1432.  
  1433. procedure TCustomDecisionGrid.SetNearestTargetCell(X, Y: Integer);
  1434. var
  1435.   Place: TButtonPlace;
  1436.   Coord: TGridCoord;
  1437.   XMax, YLabel, XLabel: Integer;
  1438.   bSwitch: Boolean;
  1439.   bNewCondition: Boolean;
  1440. begin
  1441.   if (FGridStateX = csPivoting) then
  1442.   begin
  1443.     Coord := MouseToDataCoord(X,Y);             { get grid coordinates }
  1444.     Place := GetHorzButtonPlace(X,Y);           { left, right, or middle? }
  1445.     YLabel := Coord.Y + FRowOffset;
  1446.     XLabel := Coord.X + fColOffset;
  1447.     bSwitch := (Place = bpMiddle);
  1448.     with Coord do
  1449.     begin
  1450.       if (XLabel < 0) then
  1451.         Exit
  1452.       else if (FActCols > 0) and (FActRows > 0) and
  1453.       (YLabel = -1) and (XLabel = 0) and (Place = bpLeft) then
  1454.       begin
  1455.         { Target is now the first inactive dimension } 
  1456.         bSwitch := False;
  1457.       end
  1458.       else if (Y >= -1) and (FActRows = 0) then
  1459.       begin
  1460.         { Target is now the first row dimension }
  1461.         Y := -1;
  1462.         X := 0;
  1463.         bSwitch := False;
  1464.       end
  1465.       else if (Y = -1) and (X >= 0) and (FActCols = 0) and not ((X = 0) and (Place = bpLeft)) then
  1466.       begin
  1467.         { Target is now the first column dimension }
  1468.         X := 1;
  1469.         Y := -1;
  1470.         bSwitch := False;
  1471.       end
  1472.       else if ((YLabel = -1) or (Y < FSourceCell.Y)) and (FActCols > 0) then
  1473.       begin
  1474.         { Target is in the existing column dimensions }
  1475.         Y := -1 - FRowOffset;
  1476.         if (Place = bpRight) then Inc(X);
  1477.         XMax := FActCols;
  1478.         if (X >= XMax) then
  1479.         begin
  1480.           bSwitch := False;
  1481.           X := XMax;
  1482.         end
  1483.         else if (X < 0) then
  1484.         begin
  1485.           bSwitch := False;
  1486.           X := 0;
  1487.         end
  1488.       end
  1489.       else
  1490.       begin
  1491.         { All other cases makes this a row target }
  1492.         Y := -1;
  1493.         if (Place = bpRight) then Inc(X);
  1494.         XMax := FActRows - fColOffset;
  1495.         if (X >= XMax) then
  1496.         begin
  1497.           bSwitch := False;
  1498.           X := XMax;
  1499.         end
  1500.       end
  1501.     end;
  1502.     {
  1503.       We got a new pivot situation if we have a new target cell or stop or start
  1504.       moving instead of switching dimensions.
  1505.     }
  1506.     bNewCondition := ((FTargetSwitch <> bSwitch) or (FTargetCell.X <> Coord.X)
  1507.                        or (FTargetCell.Y <> Coord.Y));
  1508.     {
  1509.      If we are going to move a dimension: eliminate both of the 2 positions where
  1510.      then dimension isn't moved at all.
  1511.     }
  1512.     if not bSwitch and bNewCondition then
  1513.       bNewCondition := ((FSourceCell.X > Coord.X) or (FSourceCell.X+1 < Coord.X)
  1514.                          or (FSourceCell.Y <> Coord.Y));
  1515.     if bNewCondition then
  1516.     begin
  1517.       InvalidateTargetCell;
  1518.       FTargetCell := Coord;
  1519.       FTargetSwitch := bSwitch;
  1520.       InvalidateTargetCell;
  1521.     end;
  1522.   end;
  1523. end;
  1524.  
  1525. {
  1526.   input a cell type and grid coordinate.
  1527.   return a row or column array and index
  1528. }
  1529.  
  1530. function TCustomDecisionGrid.GetDimensionIndex(cellType: TDecisionCellType;
  1531.  Coord: TGridCoord; var dimGroup: TDimGroup; var bExists: Boolean): Integer;
  1532. begin
  1533.   case cellType of
  1534.     ctCaptionRow:
  1535.     begin
  1536.       Result := Coord.X + fColOffset;
  1537.       dimGroup := dgRow;
  1538.       bExists := True;
  1539.     end;
  1540.     ctCaptionCol:
  1541.     begin
  1542.       Result := Coord.X;
  1543.       dimGroup := dgCol;
  1544.       bExists := True;
  1545.     end;
  1546.     else
  1547.     begin
  1548.       dimGroup := dgCol;
  1549.       Result := 0;
  1550.       bExists := False;  { Indicates: this is not an existing dimension cell. }
  1551.     end;
  1552.   end;
  1553. end;
  1554.  
  1555. procedure TCustomDecisionGrid.PerformPivot;
  1556. var
  1557.   wCoord: TDecisionCellType;
  1558.   II1, II2: Integer;
  1559.   bExist: Boolean;
  1560.   SdimGroup, DdimGroup: TDimGroup;
  1561. begin
  1562.   if (cgPivotable in FOptions) then
  1563.   begin
  1564.     wCoord := WhichCoord(FSourceCell);
  1565.     II1 := GetDimensionIndex(wCoord, FSourceCell, SdimGroup, bExist);
  1566.     if not bExist then Exit;
  1567.     { This code is for switching two existing dimensions }
  1568.     if FTargetSwitch then
  1569.     begin
  1570.       wCoord := WhichCoord(FTargetCell);
  1571.       II2 := GetDimensionIndex(wCoord, FTargetCell, DdimGroup, bExist);
  1572.       if not bExist then Exit;
  1573.       if assigned(DecisionSource) then
  1574.         DecisionSource.SwapDimIndexes(SdimGroup, DdimGroup, II1, II2, true);
  1575.     end
  1576.     { this is a move from one place to another }
  1577.     else
  1578.     begin
  1579.       if not assigned(DecisionSource) then Exit;
  1580.       wCoord := WhichCoordExCap(FTargetCell);
  1581.       II2 := GetDimensionIndex(wCoord, FTargetCell, DdimGroup, bExist);
  1582.       if (II2 >= 0) then
  1583.         DecisionSource.MoveDimIndexes(SdimGroup, DdimGroup, II1, II2, true);
  1584.     end;
  1585.   end;
  1586. end;
  1587.  
  1588. procedure TCustomDecisionGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  1589. var
  1590.   sCellType:TDecisionCellType;
  1591.   sDrawState: TDecisionDrawState;
  1592.   Index: Integer;
  1593.   ActiveIndexes: Integer;
  1594.   TPlace: TButtonPlace;
  1595.   dimGroup: TDimGroup;
  1596.   ValueIndex: Integer;
  1597.   coord: TGridCoord;
  1598.   aRect: TRect;
  1599.   i: integer;
  1600.   iRange: TDimRange;
  1601.   aString: string;
  1602.   passArray: TValueArray;
  1603.  
  1604. begin
  1605.   inherited MouseDown(Button, Shift, X, Y);
  1606.   { Allow pivoting on left mouse down only if gridstate is not already pivoting }
  1607.   { and the user has hit a cell in the row or column cpation or the header }
  1608.   if (FGridState <> gsNormal) then Exit;
  1609.   FSourceCell := MouseToDataCoord(X,Y);          { source cell is where mouse down occurs }
  1610.   GetHitTypes(FSourceCell.Y, FSourceCell.X, ValueIndex,sDrawState, sCellType);
  1611.   if (Button = mbRight) then
  1612.   begin
  1613.     if (sCellType = ctData) then
  1614.     begin
  1615.       if assigned (DecisionSource) and DecisionSource.ready then
  1616.         with DecisionSource do
  1617.         begin
  1618.           passArray := TValueArray.Create(0,0);
  1619.           try
  1620.             passArray.SortOrder := tsNone;
  1621.             if CellValueArray(FSourceCell.X, FSourceCell.Y, passArray) then
  1622.             begin
  1623.               if assigned (FOnDecisionExamineCell) then
  1624.               begin
  1625.                 FOnDecisionExamineCell(self, FSourceCell.X, FSourceCell.Y, DecisionSource.CurrentSum,
  1626.                 TValueArray(passArray));
  1627.               end
  1628.               else
  1629.               begin
  1630.                 {$IFDEF PDEBUGS}
  1631.                 DecisionCube.ShowSQLDialog(DecisionCube.GetDetailSQL(passArray,'', false));
  1632.                 {$ENDIF}
  1633.               end;
  1634.             end;
  1635.           finally
  1636.             passArray.free;
  1637.           end;
  1638.         end;
  1639.     end
  1640.     else if not (sCellType in [ctRowLabel,ctColLabel,ctCaptionRow,ctCaptionCol]) then
  1641.     begin
  1642.       FMenu.Clear;
  1643.       FMenu.AddLine(SGridMenu1, tmNone,0);
  1644.       {$IFDEF PDEBUGS}
  1645.       FMenu.AddLine(SGridMenu2, tmNone,1);
  1646.       FMenu.AddLine(SGridMenu3, tmNone,2);
  1647.       FMenu.AddLine(SGridMenu4, tmNone,3);
  1648.       {$ELSE}
  1649.       if ShowCubeEditor then
  1650.       begin
  1651.         FMenu.AddLine(SGridMenu2, tmNone,1);
  1652.       end;
  1653.       {$ENDIF}
  1654.       if assigned(DecisionSource) and DecisionSource.ready and (cgPivotable in Options) then
  1655.         with DecisionSource do
  1656.         begin
  1657.           if (nDims > 0) or (nSums > 0) then
  1658.             FMenu.AddLine('-', tmNone,-1);
  1659.           for i := 0 to nDims-1 do
  1660.           begin
  1661.             aString := GetDimensionName(i);
  1662.             if (GetState(i) = dmOpen) then
  1663.               FMenu.Addline(aString, tmChecked, i+100)
  1664.             else
  1665.               FMenu.AddLine(aString, tmNone, i+100);
  1666.           end;
  1667.           for i := 0 to nSums-1 do
  1668.           begin
  1669.             aString := GetSummaryName(i);
  1670.             if (i = DecisionSOurce.CurrentSum) then
  1671.               FMenu.Addline(aString, tmChecked, i+200)
  1672.             else
  1673.               FMenu.AddLine(aString, tmNone, i+200);
  1674.           end;
  1675.         end;
  1676.         FMenu.OnSelected := SelectGridOptions;
  1677.         FMenu.PopUpAtMe(Self, X,Y);
  1678.       end
  1679.     else if sCellType in [ctCaptionRow, ctCaptionCol, ctColPlus, ctRowPlus] then
  1680.       with FMenu do
  1681.       begin
  1682.         Clear;
  1683.         if sCellType in [ctCaptionRow, ctCaptionCol] then
  1684.         begin
  1685.           if (sCellType = ctCaptionRow) then
  1686.             dimGroup := dgRow
  1687.           else
  1688.             dimGroup := dgCol;
  1689.           if (dimGroup = dgRow) then
  1690.             Index := FSourceCell.X+FColOffset
  1691.           else
  1692.             Index := FSourceCell.X;
  1693.           if FDisplayDims[DecisionSource.GetActiveDim(dimGroup, Index,true)].SubTotals then
  1694.           begin
  1695.             FMenu.AddLine(SCaptionMenu1, tmRadio,0);
  1696.             FMenu.AddLine(SCaptionMenu2, tmNone,1);
  1697.           end
  1698.           else
  1699.           begin
  1700.             FMenu.AddLine(SCaptionMenu1, tmNone,0);
  1701.             FMenu.AddLine(SCaptionMenu2, tmRadio,1);
  1702.           end;
  1703.         end;
  1704.         if assigned(DecisionSource) and DecisionSource.ready and (cgPivotable in Options) then
  1705.           with DecisionSource do
  1706.           begin
  1707.             if ((nDims + nSums) > 0) then
  1708.               FMenu.AddLine('-', tmNone,-1);
  1709.             for i := 0 to nDims-1 do
  1710.             begin
  1711.               aString := GetDimensionName(i);
  1712.               if (GetState(i) = dmOpen) then
  1713.                 FMenu.Addline(aString, tmChecked, i+100)
  1714.               else
  1715.                 FMenu.AddLine(aString, tmNone, i+100);
  1716.             end;
  1717.             for i := 0 to nSums-1 do
  1718.             begin
  1719.               aString := GetSummaryName(i);
  1720.               if (i = DecisionSOurce.CurrentSum) then
  1721.                 FMenu.Addline(aString, tmChecked, i+200)
  1722.               else
  1723.                 FMenu.AddLine(aString, tmNone, i+200);
  1724.             end;
  1725.           end;
  1726.         FMenu.OnSelected := SelectDimOptions;
  1727.         aRect := inherited CellRect(DataToRawX(FSourceCell.X), DataToRawY(FSourceCell.Y)+1);
  1728.         FMenu.PopUpAtMe(Self, aRect.Left,aRect.Top);
  1729.       end
  1730.     else
  1731.       with FMenu do
  1732.       begin
  1733.         if (sCellType = ctRowLabel) then
  1734.           dimGroup := dgRow
  1735.         else
  1736.           dimGroup := dgCol;
  1737.         isGroupStart := dsGroupStart in sDrawState;
  1738.         if (dimGroup = dgRow) then
  1739.         begin
  1740.           ActiveIndexes := FActRows;
  1741.           Index := FSourceCell.x + fColOffset;
  1742.           Cell := FSourceCell.y;
  1743.         end
  1744.         else
  1745.         begin
  1746.           ActiveIndexes := FActCols;
  1747.           dimGroup := dgCol;
  1748.           Index := FSourceCell.Y + FRowOffset;
  1749.           Cell := FSourceCell.X;
  1750.         end;
  1751.         Clear;
  1752.         if (Index < ActiveIndexes-1) then
  1753.         begin
  1754.           iRange := DecisionSource.GetGroupExtent(dimGroup, Index, Cell);
  1755.           if (dimGroup = dgRow) then
  1756.           begin
  1757.             iRange.First := DatatoRawY(iRange.First);
  1758.             iRange.Last := DatatoRawY(iRange.Last);
  1759.           end
  1760.           else
  1761.           begin
  1762.             iRange.First := DatatoRawX(iRange.First);
  1763.             iRange.Last := DatatoRawX(iRange.Last);
  1764.           end;
  1765.           if (dimGroup = dgRow) then
  1766.           begin
  1767.             if RowHeights[iRange.First] = NoSpace then
  1768.               i := 3
  1769.             else if RowHeights[iRange.Last] = NoSpace then
  1770.               i := 2
  1771.             else
  1772.               i := 1;
  1773.           end
  1774.           else
  1775.           begin
  1776.             if ColWidths[iRange.First] = NoSpace then
  1777.               i := 3
  1778.             else if ColWidths[iRange.Last] = NoSpace then
  1779.               i := 2
  1780.             else
  1781.               i := 1;
  1782.           end;
  1783.           if (i = 1) then
  1784.             AddLine(SCaptionMenu1, tmRadio, 1)
  1785.           else
  1786.             AddLine(SCaptionMenu1, tmNone,1);
  1787.           if (i = 2) then
  1788.             AddLine(SCaptionMenu2, tmRadio, 2)
  1789.           else
  1790.             AddLine(SCaptionMenu2, tmNone,2);
  1791.           if (i = 3) then
  1792.             AddLine(SCaptionMenu3, tmRadio, 3)
  1793.           else
  1794.             AddLine(SCaptionMenu3, tmNone,3);
  1795.           AddLine('-', tmNone,-1);
  1796.         end;
  1797.         AddLine(SDrillIn, tmNone, 0);
  1798.         FMenu.OnSelected := RightMouse;
  1799.         aRect := inherited CellRect(DataToRawX(FSourceCell.X), DataToRawY(FSourceCell.Y)+1);
  1800.         FMenu.PopUpAtMe(Self, aRect.Left,aRect.Top);
  1801.       end;
  1802.   end
  1803.   else
  1804.   begin
  1805.     if (SCellType = ctColPlus) then
  1806.     begin
  1807.       Coord := MouseCoord(X,Y);
  1808.       aRect := BoxRect(Coord.X, Coord.Y, Coord.X, Coord.Y);
  1809.       if (X >= (ARect.Right-PlusWidth)) then
  1810.       begin
  1811.         if (dsOpenAfter in sDrawState) then
  1812.           DecisionSource.OpenDimIndexRight(dgCol, -1,true);
  1813.         if (dsCloseAfter in sDrawState) then
  1814.           DecisionSource.CloseDimIndexRight(dgCol, -1,true);
  1815.       end;
  1816.     end;
  1817.     if (SCellType = ctRowPlus) then
  1818.     begin
  1819.       if (dsOpenAfter in sDrawState) then
  1820.         DecisionSource.OpenDimIndexRight(dgRow, -1,true);
  1821.       if (dsCloseAfter in sDrawState) then
  1822.         DecisionSource.CloseDimIndexRight(dgRow, -1,true)
  1823.     end;
  1824.     if (sCellType in [ctCaptionRow,ctCaptionCol]) then
  1825.     begin
  1826.       TPlace := GetHorzButtonPlace(X,Y);
  1827.       if (sCellType in [ctCaptionRow]) then
  1828.         dimGroup := dgRow
  1829.       else
  1830.         dimGroup := dgCol;
  1831.       if (TPlace = bpMiddle) and (cgPivotable in Options) then
  1832.       begin
  1833.         FGridStateX := csPivoting;  { set state to pivoting } 
  1834.         FTargetCell := FSourceCell; { remember which cell is being pivoted }
  1835.         InvalidateTargetCell;
  1836.       end
  1837.       else if (TPlace = bpRight) then
  1838.       begin
  1839.         if (dimGroup = dgRow) then
  1840.           Index := FsourceCell.x + fColOffset
  1841.         else
  1842.           Index := FSourceCell.x;
  1843.         with DecisionSource do
  1844.         begin
  1845.           if ((cgOutliner in Options) and (rcNextOpen in GetRowState(DecisionSource.GetActiveDim(dimGroup, Index,true)))) then
  1846.             DecisionSource.CloseDimIndexRight(dimGroup, Index,true)
  1847.           else
  1848.             DecisionSource.OpenDimIndexRight(dimGroup, Index,true);
  1849.         end;
  1850.       end;
  1851.     end;
  1852.   end;
  1853. end;
  1854.  
  1855. procedure TCustomDecisionGrid.SelectGridOptions(Sender: TObject);
  1856. var
  1857.   Action: Integer;
  1858.   {$IFDEF PDEBUGS}
  1859.   vArray: TSmallIntArray;
  1860.   {$ENDIF}
  1861. begin
  1862.   Action := FMenu.FAction;
  1863.   case Action of
  1864.     0:  Totals := not Totals;
  1865.     1:
  1866.     begin
  1867.       if Assigned (DecisionSource) and Assigned(DecisionSource.DecisionCube) then
  1868.       begin
  1869.         DecisionSOurce.DecisionCube.SHowCubeDialog;
  1870.       end;
  1871.     end;
  1872.     {$IFDEF PDEBUGS}
  1873.     2:
  1874.     begin
  1875.       if Assigned (DecisionSource) and Assigned(DecisionSource.DecisionCube) then
  1876.       begin
  1877.         DecisionSOurce.DecisionCube.ShowqueryDialog;
  1878.       end;
  1879.     end;
  1880.     3:
  1881.     begin
  1882.       if Assigned (DecisionSource) then
  1883.         with DecisionSource do
  1884.         begin
  1885.           if Assigned(DecisionCube) then
  1886.           begin
  1887.             vArray := TSmallIntArray.create(0,0);
  1888.             try
  1889.               if GetValueArray(-1,-1, vArray) then
  1890.                 DecisionCube.ShowSQLDialog(DecisionCube.GetDetailSQL(vArray, '', false));
  1891.             finally
  1892.               vArray.free;
  1893.             end;
  1894.           end;
  1895.         end;
  1896.       end;
  1897.       {$ENDIF}
  1898.     else if Assigned (DecisionSource) then
  1899.       with DecisionSource do
  1900.       begin
  1901.         if (Action < (nDims + 100)) then
  1902.         begin
  1903.           DecisionSource.ToggleDimIndex(GetGroup(Action-100), GetIndex(Action-100,false), false);
  1904.         end
  1905.         else if (Action < (nSums + 200)) then
  1906.         begin
  1907.           DecisionSource.SetCurrentSummary(Action-200);
  1908.         end;
  1909.       end;
  1910.   end;
  1911. end;
  1912.  
  1913. procedure TCustomDecisionGrid.SelectDimOptions(Sender: TObject);
  1914. var
  1915.   iDim, Action: Integer;
  1916. begin
  1917.   Action := FMenu.FAction;
  1918.   if (Action < 100) then
  1919.   begin
  1920.     if (FMenu.Index >= 0) then
  1921.     begin
  1922.       iDim := DecisionSource.GetActiveDim(FMenu.dimGroup, Fmenu.Index,true);
  1923.       if (iDim >= 0) then
  1924.         FDisplayDims[iDim].SubTotals := (Action = 0);
  1925.     end;
  1926.   end
  1927.   else if Assigned (DecisionSource) then
  1928.     with DecisionSource do
  1929.     begin
  1930.       if (Action < (nDims + 100)) then
  1931.       begin
  1932.         DecisionSource.ToggleDimIndex(GetGroup(Action-100), GetIndex(Action-100,false), false);
  1933.       end
  1934.       else if (Action < (nSums + 200)) then
  1935.       begin
  1936.         DecisionSource.SetCurrentSummary(Action-200);
  1937.       end;
  1938.     end;
  1939. end;
  1940.  
  1941. procedure TCustomDecisionGrid.RightMouse(Sender: TObject);
  1942. var
  1943.   isSum,isBreak: boolean;
  1944.   iRange: TDimRange;
  1945.   Action: Integer;
  1946.   i: Integer;
  1947. begin
  1948. {
  1949.   Popup a menu and get one of the following user choices for this
  1950.   combination of dimension and value indicated by the Row/Col Label
  1951. }
  1952.   with FMenu do
  1953.   begin
  1954.     if (dimGroup = dgRow) and (FActRows = 0) then Exit;
  1955.     if (not (dimGroup = dgRow)) and (FActCols = 0) then Exit;
  1956.     Action := FAction;
  1957.     if (Action = 0) then
  1958.     begin
  1959.       valueIndex := DecisionSource.GetValueIndex(dimGroup,Index,Cell,isBreak,isSum);
  1960.       DecisionSource.DrillDimIndex(dimGroup,Index,ValueIndex,true);
  1961.     end
  1962.     else
  1963.     begin
  1964.       iRange := DecisionSource.GetGroupExtent(dimGroup, Index, Cell);
  1965.       if (dimGroup = dgRow) then
  1966.       begin
  1967.         iRange.First := DatatoRawY(iRange.First);
  1968.         iRange.Last := DatatoRawY(iRange.Last);
  1969.       end
  1970.       else
  1971.       begin
  1972.         iRange.First := DatatoRawX(iRange.First);
  1973.         iRange.Last := DatatoRawX(iRange.Last);
  1974.       end;
  1975.       if (iRange.First = iRange.Last) then Exit;
  1976.       FChanging := True;
  1977.       if (Action = 1) then
  1978.       begin
  1979.         for i := iRange.First to iRange.Last do
  1980.         begin
  1981.           if (dimGroup = dgRow) then
  1982.             RowHeights[i] := RowHeight
  1983.           else
  1984.             ColWidths[i] := ColWidth;
  1985.         end;
  1986.       end
  1987.       else if (Action = 2) then
  1988.       begin
  1989.         for i := iRange.First to iRange.Last-1 do
  1990.         begin
  1991.           if (dimGroup = dgRow) then
  1992.             RowHeights[i] := RowHeight
  1993.           else
  1994.             ColWidths[i] := ColWidth;
  1995.         end;
  1996.         if (dimGroup = dgRow) then
  1997.           RowHeights[iRange.Last] := NoSpace
  1998.         else
  1999.           ColWidths[iRange.Last] := NoSpace;
  2000.       end
  2001.       else if (Action = 3) then
  2002.       begin
  2003.         for i := iRange.First to iRange.Last-1 do
  2004.         begin
  2005.           if (dimGroup = dgRow) then
  2006.             RowHeights[i] := NoSpace
  2007.           else
  2008.             ColWidths[i] := NoSpace;
  2009.         end;
  2010.         if (dimGroup = dgRow) then
  2011.           RowHeights[iRange.Last] := RowHeight
  2012.         else
  2013.           ColWidths[iRange.Last] := ColWidth;
  2014.       end;
  2015.       FChanging := False;
  2016.     end;
  2017.   end;
  2018. end;
  2019.  
  2020. procedure TCustomDecisionGrid.MouseMove(Shift: TShiftState; X, Y: Integer);
  2021. begin
  2022.   inherited MouseMove(Shift, X, Y);
  2023.   if (FGridStateX = csPivoting) then
  2024.     SetNearestTargetCell(X,Y);
  2025. end;
  2026.  
  2027. procedure TCustomDecisionGrid.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  2028. begin
  2029.   inherited MouseUp(Button, Shift, X, Y);
  2030.   if (FGridStateX = csPivoting) then
  2031.   begin
  2032.     SetNearestTargetCell(X, Y);
  2033.     InvalidateTargetCell;
  2034.     FGridStateX := csNormal;
  2035.     PerformPivot;
  2036.   end;
  2037. end;
  2038.  
  2039. function TCustomDecisionGrid.GetDecisionSource: TDecisionSource;
  2040. begin
  2041.   Result := TDecisionSource(FDataLink.DecisionSource);
  2042. end;
  2043.  
  2044. procedure TCustomDecisionGrid.SetDecisionSource(Value: TDecisionSource);
  2045. var
  2046.   oldSource: TDecisionSource;
  2047. begin
  2048.   oldSource := FDatalink.DecisionSource;
  2049.   FDataLink.DecisionSource := Value;
  2050.   if (Value <> oldSource) then NewDataStructure;
  2051. end;
  2052.  
  2053. procedure TCustomDecisionGrid.CMDesignHitTest(var Msg: TCMDesignHitTest);
  2054. var
  2055.   coord: TGridCoord;
  2056.   iIndex: Integer;
  2057.   iState: TDecisionDrawState;
  2058.   iType: TDecisionCellType;
  2059.   aRect: TRect;
  2060. begin
  2061.   inherited;
  2062.   if (msg.Result <> 0) then Exit;
  2063.   if (FGridStateX = csPivoting) then
  2064.   begin
  2065.     Msg.Result := 1;
  2066.     Exit;
  2067.   end;
  2068.   Coord := MousetoDataCoord(Msg.Pos.X, Msg.Pos.Y);
  2069.   GetHitTypes(Coord.Y, Coord.X, iIndex, iState, iType);
  2070.   if (iTYPE in [ctCaptionCol, ctCaptionRow, ctColLabel, ctRowLabel, ctRowPlus]) then
  2071.   begin
  2072.     msg.Result := 1;
  2073.   end
  2074.   else if (iType = ctColPlus) then
  2075.   begin
  2076.     ARect := CellRect(Coord.X, Coord.Y);
  2077.     if (Msg.Pos.x < (ARect.Right-FIndicators.Width)) then
  2078.       msg.Result := 0
  2079.     else
  2080.       msg.Result := 1;
  2081.   end
  2082.   else
  2083.     msg.Result := 0;
  2084. end;
  2085.  
  2086. function TCustomDecisionGrid.GetData(ARow, AColumn: Integer; var SubLevel: Integer): string;
  2087. var
  2088.   iDim: Integer;
  2089.   aFormat: String;
  2090. begin
  2091.   if assigned(DecisionSource) then
  2092.   begin
  2093.     iDim := DecisionSource.CurrentSum + DecisionSource.nDims;
  2094.     aFormat := FDisplayDims[iDim].FFormat;
  2095.     if (aFormat <> '') then
  2096.     begin
  2097.       Result := FormatVariant(DecisionSource.GetDataAsVariant(Arow, AColumn, subLevel), aFormat);
  2098.     end
  2099.     else
  2100.       Result := DecisionSource.GetDataAsString(Arow, AColumn, subLevel);
  2101.   end
  2102.   else
  2103.     Result := '';
  2104. end;
  2105.  
  2106. function TCustomDecisionGrid.GetCaption(dimGroup: TDimGroup; Index: Integer): String;
  2107. var
  2108.   iDim: Integer;
  2109. begin
  2110.   Result := '';
  2111.   if assigned(DecisionSource) then
  2112.   begin
  2113.     iDim := DecisionSource.GetActiveDim(dimGroup, Index,true);
  2114.     Result := FDisplayDims[iDim].DisplayName;
  2115.     if (Result = '') then Result:= DecisionSource.GetDimensionName(iDim);
  2116.   end;
  2117. end;
  2118.  
  2119. function TCustomDecisionGrid.GetLabel(dimGroup: TDimGroup; Index: Integer;
  2120.                       ValueIndex: Integer):string;
  2121. var
  2122.   iDim: Integer;
  2123.   aFormat: String;
  2124. begin
  2125.   if assigned(DecisionSource) and (ValueIndex >= 0) then
  2126.     with DecisionSource do
  2127.     begin
  2128.       iDim := GetActiveDim(dimGroup, Index,true);
  2129.       aFormat := FDisplayDims[iDim].FFormat;
  2130.       if (aFormat <> '') then
  2131.       begin
  2132.         Result := FormatVariant(GetMemberAsVariant(iDim, ValueIndex), aFormat);
  2133.       end
  2134.       else
  2135.         Result:= DecisionSource.GetMemberAsString(iDim, ValueIndex);
  2136.     end;
  2137. end;
  2138.  
  2139. function TCustomDecisionGrid.GetCells(ACol, ARow: Integer): String;
  2140. var
  2141.   DrawState: TDecisionDrawState;
  2142.   Alignment: TAlignment;
  2143. begin
  2144.   if (ACol < -FixedCols) or (ARow < -FixedRows) or (ACol >= (ColCount - FixedCols))
  2145.   or (ARow >= (RowCount - FixedRows)) then
  2146.     Result := sGridCellError
  2147.   else
  2148.     Result := GetDataPoint(ARow, ACol, DrawState, Alignment);
  2149. end;
  2150.  
  2151. function TCustomDecisionGrid.CellDrawState(ACol, ARow: Integer;    var Value: string;
  2152.                                            var DrawState: TDecisionDrawState): boolean;
  2153. var
  2154.   Alignment: TAlignment;
  2155. begin
  2156.   if (ACol < -FixedCols) or (ARow<-FixedRows) or (ACol >= (ColCount - FixedCols))
  2157.   or (ARow >= (RowCount - FixedRows)) then
  2158.     Result := false
  2159.   else
  2160.   begin
  2161.     Value := GetDataPoint( ARow, ACol, DrawState, Alignment);
  2162.     Result := true;
  2163.   end;
  2164. end;
  2165.  
  2166. function TCustomDecisionGrid.CellValueArray(ACol, ARow: Integer; var ValueArray: TValueArray): boolean;
  2167. begin
  2168.   if not assigned(DecisionSource) then Result := false
  2169.   else
  2170.   begin
  2171.     Result := DecisionSource.GetValueArray(ACol, ARow, TSmallIntArray(ValueArray));
  2172.   end;
  2173. end;
  2174.  
  2175. function TCustomDecisionGrid.GetTotals: boolean;
  2176. var
  2177.   i: Integer;
  2178. begin
  2179.   Result := False;
  2180.   if assigned (FDisplayDims) then
  2181.   begin
  2182.     for i := 0 to FDisplayDims.Count-1 do
  2183.     begin
  2184.       if FDisplayDims[i].subtotals then
  2185.         Result := True;;
  2186.     end;
  2187.   end;
  2188. end;
  2189.  
  2190. function TCustomDecisionGrid.GetFixedRows: integer;
  2191. begin
  2192.   Result := inherited FixedRows;
  2193. end;
  2194.  
  2195. function TCustomDecisionGrid.GetFixedCols: integer;
  2196. begin
  2197.   Result := inherited FixedCols;
  2198. end;
  2199.  
  2200. function TCustomDecisionGrid.GetRowCount: integer;
  2201. begin
  2202.   Result := inherited RowCount;
  2203. end;
  2204.  
  2205. function TCustomDecisionGrid.GetColCount: integer;
  2206. begin
  2207.   Result := inherited ColCount
  2208. end;
  2209.  
  2210. procedure TCustomDecisionGrid.SetTotals(Value: boolean);
  2211. var
  2212.   i: Integer;
  2213. begin
  2214.   if assigned (FDisplayDims) then
  2215.   begin
  2216.     for i := 0 to FDisplayDims.Count-1 do
  2217.     begin
  2218.       FDisplayDims[i].subtotals := Value;
  2219.     end;
  2220.   end;
  2221. end;
  2222.  
  2223.   { Datalink methods }
  2224.   
  2225. procedure TDecisionGridDataLink.DecisionDataEvent(Event: TDecisionDataEvent);
  2226. begin
  2227.   if FBlocked then Exit;
  2228.   FBlocked := True;
  2229.   case Event of
  2230.     xeSummaryChanged:
  2231.     begin
  2232.       if assigned(FGrid) then
  2233.         FGrid.Invalidate;
  2234.     end;
  2235.     xePivot:
  2236.     begin
  2237.       if assigned(FGrid) then
  2238.         FGrid.NewGridLayout;
  2239.     end;
  2240.     xeNewMetaData:
  2241.     begin
  2242.       if assigned(FGrid) then
  2243.         FGrid.NewDataStructure;
  2244.     end;
  2245.     xeStateChanged:
  2246.     begin
  2247.       if assigned(FGrid) then
  2248.         FGrid.NewDataStructure;
  2249.     end;
  2250.     xeSourceChange:
  2251.     begin
  2252.       FGrid.SetDecisionSource(FDecisionSource);
  2253.       FGrid.NewDataStructure;
  2254.     end;
  2255.   end;
  2256.   FBlocked := False;
  2257. end;
  2258.  
  2259. constructor TDecisionGridDataLink.Create(AGrid: TCustomDecisionGrid);
  2260. begin
  2261.   FGrid := AGrid;
  2262. end;
  2263.  
  2264. destructor TDecisionGridDataLink.Destroy;
  2265. begin
  2266.   inherited Destroy;
  2267. end;
  2268.  
  2269. constructor TDisplayDims.Create(Grid: TCustomDecisionGrid; ItemClass: TDisplayDimClass);
  2270. begin
  2271.   inherited Create(ItemClass);
  2272.   FGrid := Grid;
  2273.   bQuiet := True;
  2274. end;
  2275.  
  2276. {
  2277.   The TDisplayDims class is a collection which is used to keep persistent
  2278.   properties on a dimension by dimension basis.  The collection class handles
  2279.   persistence enables the collection editor, and communicates changes in the
  2280.   collection members to the owner of the collection (in this case a grid).
  2281. }
  2282.  
  2283. function TDisplayDims.GetOwner: TPersistent;
  2284. begin
  2285.   Result := FGrid;
  2286. end;
  2287.  
  2288. function TDisplayDims.GetDisplayDim(Index: Integer): TDisplayDim;
  2289. begin
  2290.   Result := TDisplayDim(inherited Items[Index]);
  2291. end;
  2292.  
  2293. {
  2294.   Call the correct owner function to service changes in the
  2295.   collection properties, depending on the type of change
  2296. }
  2297.  
  2298. procedure TDisplayDims.NotifyOwner(aType: TDDNotifyType);
  2299. begin
  2300.   if bQuiet then Exit;
  2301.   if not (csLoading in FGrid.ComponentState) then
  2302.     case aType of
  2303.     tdDisplay: if assigned(FGrid) then
  2304.                  FGrid.NewGridLayout;
  2305.     tdMetaData:    if assigned(FGrid) then
  2306.                   FGrid.NewDataStructure;
  2307.     tdSubTotals: if assigned (FGrid) then
  2308.                    FGrid.InitializeGridCells;
  2309.     end;
  2310. end;
  2311.  
  2312. procedure TDisplayDims.SetDisplayDim(Index: Integer; Value: TDisplayDim);
  2313. begin
  2314.   Items[Index].Assign(Value);
  2315. end;
  2316.  
  2317. {
  2318.   TDisplayDim is the collection item allocated one for each dimension.  Its
  2319.   job is to allow property settings per dimension and notify the collection
  2320.   when properties change.
  2321. }
  2322.  
  2323. constructor TDisplayDim.Create(Collection: TCollection);
  2324. begin
  2325.   inherited Create(Collection);
  2326.   FOwner := Collection;
  2327.   FName := '';
  2328.   FColor := clNone;
  2329.   FSubs := True;
  2330.   FAlignment := taCenter;
  2331.   FFormat := '';
  2332. end;
  2333.  
  2334. procedure TDisplayDim.assign(Value: TPersistent);
  2335. begin
  2336.   if (Value is TDisplayDim) then
  2337.   begin
  2338.     FName := TDisplayDim(Value).FName;
  2339.     FColor := TDisplayDim(Value).FColor;
  2340.     FSubs := TDisplayDim(Value).FSubs;
  2341.     FAlignment := TDisplayDim(Value).FAlignment;
  2342.     FFormat := TDisplayDim(Value).FFormat;
  2343.   end;
  2344. end;
  2345.  
  2346. procedure TDisplayDim.SetName(Value: string);
  2347. begin
  2348.   fName := Value;
  2349.   NotifyCollection(tdDisplay);
  2350. end;
  2351.  
  2352. procedure TDisplayDim.SetFieldName(Value: string);
  2353. begin
  2354.   if (not assigned(FOwner)) or (not assigned(TDisplayDims(FOwner).FGrid)) then
  2355.     Exit;
  2356.   if (csLoading in TDisplayDims(FOwner).FGrid.ComponentState) then
  2357.   begin
  2358.     fFieldName := Value;
  2359.     NotifyCollection(tdMetaData);
  2360.   end;
  2361. end;
  2362.  
  2363. procedure TDisplayDim.SetFormat(Value: String);
  2364. begin
  2365.   FFormat := Value;
  2366.   NotifyCollection(tdMetaData);
  2367. end;
  2368.  
  2369. procedure TDisplayDim.SetAlignment(Value: TAlignment);
  2370. begin
  2371.   fAlignment := Value;
  2372.   NotifyCollection(tdDisplay);
  2373. end;
  2374.  
  2375. procedure TDisplayDim.SetColor(Value: TColor);
  2376. begin
  2377.   fColor := Value;
  2378.   NotifyCollection(tdDisplay);
  2379. end;
  2380.  
  2381. procedure TDisplayDim.SetSubs(Value: Boolean);
  2382. begin
  2383.   fSubs := Value;
  2384.   NotifyCollection(tdMetaData);
  2385. end;
  2386.  
  2387. procedure TDisplayDim.NotifyCollection(aType: TDDNotifyType);
  2388. begin
  2389.   TDisplayDims(FOwner).NotifyOwner(aType);
  2390. end;
  2391.  
  2392. end.
  2393.  
  2394.  
  2395.